package cn.com.zp.util.base;

import java.io.ByteArrayOutputStream;

/**
 * Byte operation class
 * 
 * @author peng.zhang8@gmail.com
 * @since 2012/9/12
 */
public class ByteUtils {
	/***
	 * Convert a String of hexadecimal digits into the corresponding byte array
	 * by encoding each two hexadecimal digits as a byte.
	 * 
	 * @param digits
	 * @return
	 */
	public static byte[] hexStringToByteArray(String digits) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		for (int i = 0; i < digits.length(); i += 2) {
			char c1 = digits.charAt(i);
			if ((i + 1) >= digits.length()) {
				throw new IllegalArgumentException("hexUtil.odd");
			}
			char c2 = digits.charAt(i + 1);
			byte b = 0;
			if ((c1 >= '0') && (c1 <= '9'))
				b += ((c1 - '0') * 16);
			else if ((c1 >= 'a') && (c1 <= 'f'))
				b += ((c1 - 'a' + 10) * 16);
			else if ((c1 >= 'A') && (c1 <= 'F'))
				b += ((c1 - 'A' + 10) * 16);
			else
				throw new IllegalArgumentException("hexUtil.bad");

			if ((c2 >= '0') && (c2 <= '9'))
				b += (c2 - '0');
			else if ((c2 >= 'a') && (c2 <= 'f'))
				b += (c2 - 'a' + 10);
			else if ((c2 >= 'A') && (c2 <= 'F'))
				b += (c2 - 'A' + 10);
			else
				throw new IllegalArgumentException("hexUtil.bad");
			baos.write(b);
		}
		return (baos.toByteArray());

	}

	/**
	 * Convert a byte array into a printable format containing a String of
	 * hexadecimal digit characters (two per byte).
	 * 
	 * @see this method consume too much memory, especailly when large byte
	 *      array.
	 * 
	 * @param bytes
	 *            Byte array representation
	 */
	public static String convertByteArrayToHexStr(byte bytes[]) {

		StringBuffer sb = new StringBuffer(bytes.length * 2);
		for (int i = 0; i < bytes.length; i++) {
			sb.append(convertDigitToHexChar((int) (bytes[i] >> 4)));
			sb.append(convertDigitToHexChar((int) (bytes[i] & 0x0f)));
		}
		return (sb.toString());

	}

	/**
	 * convert byte array into hex string, with , as seperator
	 * 
	 * @see this method consume too much memory, especailly when large byte
	 *      array.
	 * @param bytes
	 * @return
	 */
	public static String convertByteArrayToHexStr2(byte bytes[]) {

		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < bytes.length; i++) {
			sb.append(convertDigitToHexChar((int) (bytes[i] >> 4)));
			sb.append(convertDigitToHexChar((int) (bytes[i] & 0x0f)));
			sb.append(",");
		}
		return (sb.toString().substring(0, sb.length() - 1));

	}

	/**
	 * Convert the specified value (0 .. 15, i.e. 4bits) to the corresponding
	 * hexadecimal digit.
	 * 
	 * @param value
	 *            Value to be converted
	 */
	private static char convertDigitToHexChar(int value) {
		value = value & 0x0f;
		if (value >= 10)
			return ((char) (value - 10 + 'a'));
		else
			return ((char) (value + '0'));

	}

	public static String convertByteToHexStr(byte value) {
		StringBuffer sb = new StringBuffer();
		sb.append(convertDigitToHexChar((int) (value >> 4)));
		sb.append(convertDigitToHexChar((int) (value & 0x0f)));

		return (sb.toString());

	}

	/**
	 * Convert an int to a byte array
	 * 
	 * @param value
	 *            int
	 * @return byte[]
	 */
	public static byte[] intToByteArray(int value) {
		byte[] b = new byte[4];

		for (int i = 0; i < 4; i++) {
			int offset = (b.length - 1 - i) * 8;
			b[i] = (byte) ((value >> offset) & 0xFF); 
		}
		return b;
	}

	/**
	 * change byte array into a unsigned byte array
	 * 
	 * @param source
	 * @return
	 */
	public static byte[] toUnsignedByteArray(byte[] source) {
		int model = 256;
		if (source == null || source.length == 0) {
			return new byte[0];
		}
		byte[] dest = new byte[source.length];
		for (int i = 0; i < source.length; i++) {
			int tmp = ((source[i] + model) % model) & 0xff;
			dest[i] = (byte) tmp;
		}
		return dest;
	}

	/**
	 * Convert the byte array to an int starting from the given offset.
	 * 
	 * @param b
	 *            The byte array
	 * @param offset
	 * 
	 * @return The integer
	 */

	public static int byteArrayToInt(byte[] b) {
		if (b.length > 4) {
			throw new RuntimeException("more than 4 byte");
		}
		int value = 0;
		for (int i = 0; i < b.length; i++) {
			int shift = (b.length - 1 - i) * 8;
			value += (b[i] & 0xFF) << shift;
		}
		return value;
	}

}
